﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AMS.Core;
using System.Timers;

namespace AMS.Core.Services
{
    public class SessionService : ISessionService
    {
        private Dictionary<string, string> _sessions;
        private Dictionary<string, DateTime> _sessionUpdates;

        private Timer _timer;

        private TimeSpan _timeout;
        public TimeSpan Timeout
        {
            get { return _timeout; }
            set { _timeout = value; }
        }

        public event EventHandler<TimeoutEventArgs> TimedOut;
        protected void RaiseTimedOut(TimeoutEventArgs args)
        {
            EventHandler<TimeoutEventArgs> handler = TimedOut;
            if (handler != null)
                handler(this, args);
        }

        public SessionService()
            : this (new TimeSpan(0, 10, 0))
        { }

        public SessionService(TimeSpan timeout)
        {
            _timeout = timeout;
            _sessions = new Dictionary<string, string>();
            _sessionUpdates = new Dictionary<string, DateTime>();
            _timer = new Timer(1000d);
            _timer.Elapsed += new ElapsedEventHandler(HandleTimerTick);
        }

        public object StartSession(string identifier)
        {
            if (HasSession(identifier))
                ExceptionHandler.Exception("already in session");

            string sessionVariable = Guid.NewGuid().ToString();

            _sessions.Add(sessionVariable, identifier);
            _sessionUpdates.Add(sessionVariable, DateTime.Now);

            return sessionVariable;
        }

        public bool HasSession(string identifier)
        {
            return (_sessions.ContainsValue(identifier));
        }

        public bool IsValidSession(string identifier, object sessionVariable)
        {
            return _sessions.ContainsKey((string)sessionVariable)
                && _sessions[(string)sessionVariable] == identifier;
        }

        public bool IsValidSession(object sessionVariable)
        {
            return _sessions.ContainsKey((string)sessionVariable);
        }

        public void UpdateSession(object sessionVariable)
        {
            if (_sessionUpdates.ContainsKey((string)sessionVariable))
                _sessionUpdates[(string)sessionVariable] = DateTime.Now;
            else
                ExceptionHandler.Exception("no valid session found");
        }

        public void EndSession(object sessionVariable)
        {
            if (_sessions.ContainsKey((string)sessionVariable))
                _sessions.Remove((string)sessionVariable);
        }

        protected void HandleTimerTick(object sender, ElapsedEventArgs e)
        {
            if (_timeout <= TimeSpan.Zero)
                return;

            // check all sessions and make sure none are expired
            DateTime checkTime = DateTime.Now;
            List<string> timedOutSessions = new List<string>();

            foreach (string key in _sessionUpdates.Keys)
            {
                if (_sessionUpdates[key] + _timeout >= checkTime)
                {
                    timedOutSessions.Add(key);
                    RaiseTimedOut(new TimeoutEventArgs(_sessions[key]));
                }
            }

            foreach (string session in timedOutSessions)
            {
                _sessions.Remove(session);
                _sessionUpdates.Remove(session);
            }
        }

        public string ResolveIdentifier(object sessionVariable)
        {
            string sv = sessionVariable as string;
            if (_sessions.ContainsKey(sv))
                return _sessions[sv];

            return null;
        }
    }
}
